package com.bao.auth.server.biz.service.auth.impl;

import com.bao.auth.dto.auth.LoginDTO;
import com.bao.auth.dto.auth.ResourceQueryDTO;
import com.bao.auth.dto.auth.UserDTO;
import com.bao.auth.entity.auth.Resource;
import com.bao.auth.entity.auth.User;
import com.bao.auth.server.biz.service.auth.ResourceService;
import com.bao.auth.server.biz.service.auth.UserService;
import com.bao.common.constant.CacheKey;
import com.bao.core.base.R;
import com.bao.core.exception.code.ExceptionCode;
import com.bao.dozer.DozerUtils;
import com.bao.jwt.server.utils.JwtTokenServerUtils;
import com.bao.jwt.utils.JwtUserInfo;
import com.bao.jwt.utils.Token;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
import net.oschina.j2cache.CacheChannel;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class AuthManager {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private JwtTokenServerUtils jwtTokenServerUtils;
    
    @Autowired
    private DozerUtils dozerUtils;

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private CacheChannel cacheChannel;
    
    /**
     * 登录验证
     * @param account 账号
     * @param password 密码
     * @return
     */
    public R<LoginDTO> login(String account,String password){
        R<User> userR = check(account, password);
        Boolean isError = userR.getIsError();
        if(isError){
            return R.fail("登录认证失败");
        }
        
        //为用户生产jwt令牌
        User user = userR.getData();
        Token token = generateUserToken(user);
        
        //查询当前用户可以访问的资源权限
        List<Resource> userResource = resourceService.findVisibleResource(ResourceQueryDTO.builder().userId(user.getId()).build());
        log.info("当前用户拥有的资源权限为：" + userResource);
        
        //用户对应的资源权限（给前端使用）
        List<String> permissionList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(userResource)) {
            permissionList = userResource.stream().map(Resource::getCode).collect(Collectors.toList());
            
            //将用户对应的权限 存入缓存 （给后端网关使用）
            List<String> visibleResource = userResource.stream().map(resource -> {
                return resource.getMethod() + resource.getUrl();
            }).collect(Collectors.toList());
            //缓存权限数据
            cacheChannel.set(CacheKey.USER_RESOURCE,user.getId().toString(), visibleResource);
        }

        /**
         * 封装返回结果
         */
        LoginDTO loginDTO = LoginDTO.builder()
                .user(dozerUtils.map(userR.getData(), UserDTO.class))
                .token(token)
                .permissionsList(permissionList)
                .build();
        return R.success(loginDTO);
        
    }

    /**
     * 根据查询出的用户生成token令牌
     * @param user 用户信息
     * @return token
     */
    public Token generateUserToken(User user){
        JwtUserInfo jwtUserInfo = new JwtUserInfo(user.getId(), user.getAccount(), user.getName(), user.getOrgId(), user.getStationId());
        Token token = jwtTokenServerUtils.generateUserToken(jwtUserInfo, null);
        return token;
    }

    /**
     * 账号、密码校验
     * @param account 账号
     * @param password 密码
     * @return
     */
    public R<User> check(String account, String password) {
        //根据账号查询用户
        User user = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getAccount, account));
        
        //将前端提交的密码进行 md5 加密 (apache的包)
        String md5Hex = DigestUtils.md5Hex(password);
        
        if (user == null || !user.getPassword().equals(md5Hex)) {
           return R.fail(ExceptionCode.JWT_USER_INVALID);
        }
        return R.success(user);
    }
}
